View属性动画(进阶)

本文主要是学习笔记,学习建议直接去看HenCoder视频教学
作业原地址:课程作业地址
交作业地址:交作业

ObjectAnimator的两个知识点:

  • PropertyValuesHolder和AnimatorSet的使用
  • TypeEvaluator的使用

PropertyValuesHolder和AnimatorSet的使用:

View属性动画(基础)中写到了ViewPropertyAnimator的组合动画,直接连续设置就可以了,会使用相同的Interpolator和Duration。
ObjectAnimator的组合动画需要用到PropertyValuesHolder:

  PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("scaleX", 0, 1);
  PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("scaleY", 0, 1);
  PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("alpha", 0, 1);
  ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(view, holder1, holder2, holder3);
  objectAnimator.start();

但是有时候需求不是这样的,需要每个动画使用不同Interpolator或Duration。使用AnimatorListener当然可以实现,但是还有更简单的实现方式,需要使用AnimatorSet。
比如:

// 要求 1: animator1 先执行,animator2 在 animator1 完成后立即开始
// 要求 2: animator2 和 animator3 同时开始
  ObjectAnimator animator1 = ObjectAnimator.ofFloat(view, "alpha", 0, 1);
  ObjectAnimator animator2 = ObjectAnimator.ofFloat(view, "translationX", 0, 100);
  ObjectAnimator animator3 = ObjectAnimator.ofFloat(view, "rotation", 0, 360);

使用AnimatorSet实现方式:

  AnimatorSet animatorSet = new AnimatorSet();
  animatorSet.play(animator1).before(animator2);
  animatorSet.play(animator2).with(animator3);
  animatorSet.start();

PropertyValuesHolder还有个比较常用的功能:通过ofKeyframe(),设置关键帧。比如假设有个ProgressView类,需要实现progress的回弹效果:

  Keyframe startFrame = Keyframe.ofFloat(0f, 0);
  Keyframe middleFrame = Keyframe.ofFloat(0.5f, 100);
  Keyframe endFrame = Keyframe.ofFloat(1f, 80);
  PropertyValuesHolder propertyValuesHolder = PropertyValuesHolder.ofKeyframe("progress", startFrame, middleFrame, endFrame);

  ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(view, propertyValuesHolder);
  objectAnimator.start();

这样效果就到达了,从0开始,动画执行到一半的时候,进度已经达到100,然后在剩下的时间回弹到80。


TypeEvaluator的使用

TypeEvaluator是干什么的?为什么要用TypeEvaluator?
TypeEvaluator能根据动画属性数值的变换,达到我们想要的效果,系统已经提供了一些TypeEvaluator,我们可以自定义TypeEvaluator。
举个例子,用ObjectAnimator去设置红色渐变为绿色,色值是ofInt,那啥都不管,直接这样撸:

  ObjectAnimator animator = ObjectAnimator.ofInt(view, "color", 0xffff0000, 0xff00ff00);
  animator.setDuration(2000);
  animator.start();

效果
逗逼的渐变

确实实现了渐变,但绝对是在逗逼。因为系统会把色值从0xffff0000按Int直接做加法到0xff00ff00,但效果看起来绝不是我们想要的渐变。我们需要的是人类感觉的渐变,而不是机器所谓的渐变。这里需要制定动画按什么规则变,就需要用到TypeEvaluator,比如添加如下设置:

animator.setEvaluator(new ArgbEvaluator());

这样,就使用系统提供好的ArgbEvaluator实现了人眼感觉的渐变:


argb变化规则

或者不使用系统的ArgbEvaluator,想hsv变换规则,自定义HsvEvaluator:

    private class HsvEvaluator implements TypeEvaluator<Integer> {
        float[] startHsv = new float[3];
        float[] endHsv = new float[3];
        float[] outHsv = new float[3];

        @Override
        public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
            // 把 ARGB 转换成 HSV
            Color.colorToHSV(startValue, startHsv);
            Color.colorToHSV(endValue, endHsv);

            // 计算当前动画完成度(fraction)所对应的颜色值
            if (endHsv[0] - startHsv[0] > 180) {
                endHsv[0] -= 360;
            } else if (endHsv[0] - startHsv[0] < -180) {
                endHsv[0] += 360;
            }
            outHsv[0] = startHsv[0] + (endHsv[0] - startHsv[0]) * fraction;
            if (outHsv[0] > 360) {
                outHsv[0] -= 360;
            } else if (outHsv[0] < 0) {
                outHsv[0] += 360;
            }
            outHsv[1] = startHsv[1] + (endHsv[1] - startHsv[1]) * fraction;
            outHsv[2] = startHsv[2] + (endHsv[2] - startHsv[2]) * fraction;

            // 计算当前动画完成度(fraction)所对应的透明度
            int alpha = startValue >> 24 + (int) ((endValue >> 24 - startValue >> 24) * fraction);

            // 把 HSV 转换回 ARGB 返回
            return Color.HSVToColor(alpha, outHsv);
        }
    }
animator.setEvaluator(new HsvEvaluator());

效果:


hsv变化规则

再来个简单的自定义TypeEvaluator,帮助理解,比如要是下面效果:


自定义View中:

    public PointF getPosition() {
        return position;
    }

    public void setPosition(PointF position) {
        if (position != null) {
            this.position.set(position);
            invalidate();
        }
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        float innerPaddingLeft = RADIUS * 1;
        float innterPaddingRight = RADIUS * 1;
        float innterPaddingTop = RADIUS * 1;
        float innterPaddingBottom = RADIUS * 3;
        float width = getWidth() - innerPaddingLeft - innterPaddingRight - RADIUS * 2;
        float height = getHeight() - innterPaddingTop - innterPaddingBottom - RADIUS * 2;

        canvas.drawCircle(innerPaddingLeft + RADIUS + width * position.x, innterPaddingTop + RADIUS + height * position.y, RADIUS, paint);
    }

自定义PointFEvaluator:

    private class PointFEvaluator implements TypeEvaluator<PointF> {

        PointF pointF = new PointF();
        @Override
        public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
            float x = startValue.x + (fraction * (endValue.x - startValue.x));
            float y = startValue.y + (fraction * (endValue.y - startValue.y));
            pointF.set(x, y);
            return pointF;
        }
    }

设置动画:

  ObjectAnimator animator = ObjectAnimator.ofObject(view, "position",
                        new PointFEvaluator(), new PointF(0, 0), new PointF(1, 1));
  animator.setInterpolator(new LinearInterpolator());
  animator.setDuration(1000);
  animator.start();

哦了,感谢HenCoder

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270